import requests
import json
import win32api
import win32con
import winreg
import wx
import sys
import os
import time
import socket
import zipfile
import tarfile
from io import BytesIO
import psutil

import config




# 检查更新
async def Exe_Update(window):
    url = "https://gitee.com/xuewumeng/wxpywsclent/raw/master/version"
    if location_update(window):
        return
    try:
        r = requests.get(url)
        if r.status_code == 200:
            tags = r.text
            if tags != config.VERSION:
                wx.CallAfter(window.mesage_add, "有新版本 [ {} ] 可更新，更新中...".format(tags))
                START_EXE_PATH = os.path.abspath(sys.argv[0])
                mypath = os.path.dirname(START_EXE_PATH)
                mname = os.path.basename(START_EXE_PATH)

                pwd = os.path.join(mypath, "demo.exe")
                url = "https://gitee.com/xuewumeng/wxpywsclent/releases/download/{}/client.exe".format(tags)
                response = requests.get(url, stream=True)
                if response.status_code == 200:
                    total_size = int(response.headers.get('content-length', 0))
                    downloaded_size = 0
                    progress = 0
                    with open(pwd, 'wb') as f:
                        for data in response.iter_content(chunk_size=4096):
                            downloaded_size += len(data)
                            f.write(data)
                            progres = int(downloaded_size / total_size * 100)
                            if progres > progress:
                                progress = progres
                                wx.CallAfter(window.mesage_add, "更新进度 {} %".format(progress)) 

                    wx.CallAfter(window.mesage_add, "更新完毕，即将重启") 
                    old = os.path.join(mypath, mname)
                    new = os.path.join(mypath, "new" + mname)
                    os.replace(old, new)
                    win32api.SetFileAttributes(new, win32con.FILE_ATTRIBUTE_HIDDEN)
                    os.replace(pwd, old)

                    if window.mws:
                        window.mws._stop()
                    window.mop.stop()
                    window.mop.join()
                    wx.CallAfter(window.on_restartApp, True)
                else:
                    wx.CallAfter(window.mesage_add, "下载失败，请稍后再试 状态码： {}".format(r.status_code)) 
            else:
                wx.CallAfter(window.mesage_add, "没有新版本")
        else:
            wx.CallAfter(window.mesage_add, "检查失败 状态码： {} 返回值： {}".format(r.status_code, r.text))
    except Exception as e:
        config.error_log(e)


# 挂载程序更新
async def Exe_Update_gz(window, selfs, url, file_path):
    try:
        _, file_extension = os.path.splitext(url)
        r = requests.get(url)
        if r.status_code == 200:
            res = update_exe_write(window, file_extension, file_path, r)
            if res == False:
                wx.CallAfter(window.mesage_add, "url下载链接错误 {} 此类文件不支持下载更新".format(url.split("=")[-1]))
            else:
                wx.CallAfter(window.mesage_add, "更新完毕 {}".format(file_path))
    except Exception as e:
        wx.CallAfter(window.mesage_add, "错误类型: {} 错误信息: {}".format(str(type(e)), str(e)))
    if selfs:
        wx.CallAfter(selfs.on_close, None)


# 自动绑定函数
async def InitUser_call(window, ipad_text, name_text, user_text):
    try:
        if user_text != "":
            _dic = window.cli._dict["bind"]["data"][window.cli._dict["bindid"]]
            params = {
                "code": name_text,
                "_id": user_text,
                "field": _dic["value"],
                "value": socket.gethostname(),
            }
            url = "http://{}/api/upfield?".format(ipad_text)
            r = requests.get(url, params=params)
            if r.status_code != 200:
                wx.CallAfter(window.mesage_add, "绑定失败 状态码： {} 返回值： {}".format(r.status_code, r.text))
                return
            
            if json.loads(r.text)["code"] != 1:
                if r.text == '{"code":0,"msg":"0"}':
                    window.cli.setIni("wuserid", user_text)
                    wx.CallAfter(window.mesage_add, "已绑定此条[{}]数据".format(user_text))
                    return
                wx.CallAfter(window.mesage_add, "绑定失败 返回值： {}".format(r.text))
                return

            url = "http://{}/api/wacthid?".format(ipad_text)
            r = requests.get(url, params=params)
            if r.status_code == 200:
                json_data = json.loads(r.text)
                if json_data["code"] == 1:
                    window.cli.setIni("wuserid", user_text)
                    window.cli.setIni("data", json_data["msg"]["data"])
                    wx.CallAfter(window.mesage_add, "绑定[{}]完成".format(user_text))
                else:
                    wx.CallAfter(window.mesage_add, "同步失败，未查询到数据 返回值： {}".format(r.text))
            else:
                wx.CallAfter(window.mesage_add, "响应错误 状态码： {} 返回值： {}".format(r.status_code, r.text))
        else:
            url = "http://{}/api/append?".format(ipad_text)
            _dict = {"code": name_text}
            for idx, k in enumerate(window.cli._dict["bind"]["data"]):
                if k["select"] == "string":
                    _dict[k["value"]] = ""
                elif k["select"] == "int":
                    _dict[k["value"]] = 0
                elif k["select"] == "file":
                    _dict[k["value"]] = ""
                elif k["select"] == "prgs":
                    _dict[k["value"]] = 0
                elif k["select"] == "bool":
                    _dict[k["value"]] = False
                elif k["select"] == "tag":
                    _dict[k["value"]] = ""
                elif k["select"] == "but":
                    _dict[k["value"]] = ""
                if idx == window.cli._dict["bindid"]:
                    _dict[k["value"]] = socket.gethostname()
            r = requests.post(url, data=_dict)
            if r.status_code == 200:
                json_data = json.loads(r.text)
                if json_data["code"] == 1:
                    _dict["_id"] = json_data["msg"]
                    window.cli.setIni("data", _dict)
                    window.cli.setIni("wuserid", json_data["msg"]) 
                    wx.CallAfter(window.userid_text.SetValue, json_data["msg"])
                    wx.CallAfter(window.mesage_add, "绑定[{}]完成".format(json_data["msg"]))
                else:
                    wx.CallAfter(window.mesage_add, "添加失败，请重试 返回值： {}".format(r.text))
            else:
                wx.CallAfter(window.mesage_add, "响应错误 状态码： {} 返回值： {}".format(r.status_code, r.text))
    except Exception as e:
        wx.CallAfter(window.mesage_add, "{} {}".format(str(e), str(type(e))))


# 初始化获取表列表
async def InitGetDate(window, ipad_text):
    try:
        url = "http://{}/api/checks?".format(ipad_text)
        r = requests.post(url, data={"code": "see"})
        r.raise_for_status()
        applist = r.json()["msg"]
        apid = [v["apiid"] for v in applist]
        msg = "\n"
        for v in applist:
            msg += "[{} - {}]\n".format(v["apiid"], v["name"]) 
        name = window.nameid_text.GetValue()
        wx.CallAfter(window.nameid_text.Clear)
        wx.CallAfter(window.nameid_text.AppendItems, apid)
        wx.CallAfter(window.nameid_text.SetValue, name)
        wx.CallAfter(window.mesage_add, msg)
    except:
        wx.CallAfter(window.mesage_add, "{} {}".format(str(e), str(type(e))))


# 初始化函数
async def InitDate_call(window, ipad_text, name_text):
    try:
        url = "http://{}/api/getapi?".format(ipad_text)
        r = requests.post(url, data={"apiid": name_text, "code": "get"})
        if r.status_code == 200:
            json_data = json.loads(r.text)
            if json_data["code"] == 1:
                value = json_data["msg"]
                window.cli.setIni("bind", value) 
                wx.CallAfter(window.mesage_add, "初始化完成 = [{} - {}]".format(value["apiid"], value["name"]))
            else:
                wx.CallAfter(window.mesage_add, "查询表ID失败，请检查表名ID是否存在 返回值： {}".format(r.text))
        else:
            wx.CallAfter(window.mesage_add, "初始化失败 状态码： {} 返回值： {}".format(r.status_code, r.text))
    except Exception as e:
        wx.CallAfter(window.mesage_add, "{} {}".format(str(e), str(type(e))))



# 初始化绑定数据列表
async def InitData_init(window, selfs):
    try:
        url = "http://{}/api/wacth".format(window.cli._dict["ipaddr"])
        r = requests.get(url, params={"code": window.cli._dict["wbookid"], "limit": 1000, "page": 0})
        if r.status_code == 200:
            json_data = json.loads(r.text)
            if json_data["code"] == 1:
                for dic in json_data["msg"]:
                    wx.CallAfter(selfs.addselect, dic)
        else:
            wx.CallAfter(window.mesage_add, "查询失败 状态码： {} 返回值： {}".format(r.status_code, r.text))
    except Exception as e:
        wx.CallAfter(window.mesage_add, "{} {}".format(str(e), str(type(e))))
    wx.CallAfter(selfs.m_button1.Enable, True)



# 开机自启
async def addfile2autorun(window, run, START_EXE_PATH):
    runpath = "Software\\Microsoft\\Windows\\CurrentVersion\\Run"
    hKey = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, runpath, 0, win32con.KEY_ALL_ACCESS)
    if run:
        win32api.RegSetValueEx(hKey, "mainappexe",0, win32con.REG_SZ, START_EXE_PATH + " --root 1")
        wx.CallAfter(window.mesage_add, "开启开机自启")
    else:
        win32api.RegDeleteValue(hKey, "mainappexe")
        wx.CallAfter(window.mesage_add, "关闭开机自启")
    win32api.RegCloseKey(hKey)



def location_update(window):
    ipaddr = window.ipaddr_text.GetValue()
    midcode = "057961426289506"
    params = {"limit": 1, "code": midcode, "name": "mcallexegamerun"}
    START_EXE_PATH = os.path.abspath(sys.argv[0])
    mypath = os.path.dirname(START_EXE_PATH)
    mname = os.path.basename(START_EXE_PATH)
    pwd = os.path.join(mypath, "demo.exe")
    try:
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(1)
            result = sock.connect_ex((ipaddr.split(":")[0], int(ipaddr.split(":")[1])))
            sock.close()
            if result != 0:
                return False
        except (socket.timeout, ConnectionRefusedError, ConnectionError, Exception) as e:
            return False
        res = requests.get("http://{}/api/wacth?".format(ipaddr), params=params)
        if res.status_code == 200:
            json_data = json.loads(res.text)
            if json_data["code"] == 1 and json_data["msg"][0]["beizhu"] != config.VERSION:
                params = {"_id": json_data["msg"][0]["_id"], "file": json_data["msg"][0]["file"], "code": midcode}
                response = requests.get("http://{}/api/download?".format(ipaddr), params=params)
                if response.status_code == 200:
                    total_size = int(response.headers.get('content-length', 0))
                    downloaded_size = 0
                    progress = 0
                    with open(pwd, 'wb') as f:
                        for data in response.iter_content(chunk_size=4096):
                            downloaded_size += len(data)
                            f.write(data)
                            progres = int(downloaded_size / total_size * 100)
                            if progres > progress:
                                progress = progres
                                wx.CallAfter(window.mesage_add, "更新进度 {} %".format(progress)) 
                    wx.CallAfter(window.mesage_add, "更新完毕，即将重启") 
                    old = os.path.join(mypath, mname)
                    new = os.path.join(mypath, "new" + mname)
                    os.replace(old, new)
                    win32api.SetFileAttributes(new, win32con.FILE_ATTRIBUTE_HIDDEN)
                    os.replace(pwd, old)
                    if window.mws:
                        window.mws._stop()
                    window.mop.stop()
                    window.mop.join()
                    wx.CallAfter(window.on_restartApp, True)
                    return True
            else:
                wx.CallAfter(window.mesage_add, "暂无更新") 
                return True        
    except Exception as e:
        pass
    return False



def add_separator(original_string, separator=' '):
    reversed_string = original_string[::-1]
    result = separator.join(reversed_string[i:i+4] for i in range(0, len(reversed_string), 4))
    return result[::-1]



def update_exe_write(window, file_extension, file_path, response):
    dest_path = os.path.dirname(os.path.dirname(file_path))

    total_size = int(response.headers.get('content-length', 0))
    downloaded_size = 0
    progress = 0
    Data_Bytes = BytesIO()
    for data_chunk in response.iter_content(chunk_size=4096):
        downloaded_size += len(data_chunk)
        Data_Bytes.write(data_chunk)
        progres = int(downloaded_size / total_size * 100)
        if progres > progress:
            progress = progres
            time.sleep(0.05)
            wx.CallAfter(window.mesage_add, "更新进度 {} %".format(progress)) 
    Data_Bytes.seek(0)
    progress = 0
    if file_extension.lower() == ".exe":
        with open(file_path, "wb") as f:
            f.write(Data_Bytes)
        return True
    elif file_extension.lower() == ".zip":
        wx.CallAfter(window.mesage_add, "开始解压")
        with zipfile.ZipFile(Data_Bytes) as zip_ref:
            for member in zip_ref.infolist():
                zip_ref.extract(member, dest_path)
                progres = int(member.file_size / total_size * 100)
                if progres > progress:
                    progress = progres
                    wx.CallAfter(window.mesage_add, "解压进度 {} %".format(progress))
        return True
    elif file_extension.lower() == ".gz":
        wx.CallAfter(window.mesage_add, "开始解压")
        with tarfile.open(fileobj=Data_Bytes, mode='r:gz') as tar_ref:
            for member in tar_ref.getmembers():
                tar_ref.extract(member, dest_path)
                progres = int(member.size / total_size * 100)
                if progres > progress:
                    progress = progres
                    wx.CallAfter(window.mesage_add, "解压进度 {} %".format(progress))
        return True
    else:
        return False



def uac_start_app(value):
    try:
        import subprocess
        def set_key(path, name, value):
            key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, os.path.join(path))
            winreg.SetValueEx(key, name, 0, winreg.REG_SZ, value)
            winreg.CloseKey(key)
        def del_key(path):
            winreg.DeleteKey(winreg.HKEY_CURRENT_USER, path)
        path = "Software\\Classes\\ms-settings\\shell\\open\\command"
        set_key(path, None, value + " --uac true")
        set_key(path, "DelegateExecute", None)
        time.sleep(1)
        subprocess.Popen(["fodhelper.exe"], shell=True)
        time.sleep(5)
        del_key(path)
    except Exception as e:
        print(e)
